#!/usr/bin/env python
# $Id: autopirate.py,v 1.11 2007/12/07 19:21:05 jim Exp $
# (c) 2007 Jim Geovedi <jim@geovedi.com>
#
# Distributed under new BSD license.

from ConfigParser import ConfigParser
from mechanize import Browser, LinkNotFoundError
from os import path, stat
from random import choice
from re import search, compile, sub
from sys import exit
from time import strftime, sleep
from urllib import urlencode
from urllib2 import URLError, HTTPError, HTTPDefaultErrorHandler

DEBUG = False

class pirates:
	def __init__(self):
		self.browser = Browser()
		self.browser.set_handle_robots(False)
		self.user_agent = "Mozilla/5.0 (compatible; MSIE 7.0b;)"
		self.browser.addheaders = [
				("User-agent", self.user_agent),
				("Proxy-Connection", "keep-alive")]
		self.browser.set_debug_redirects(DEBUG)
		self.browser.set_debug_responses(DEBUG)
		self.browser.set_debug_http(DEBUG)
		(self.email, self.password) = self.getconf()

	def start(self):
		self.log("Pirates bot started by %s." % self.email)
		self.browser.open("http://apps.facebook.com/login.php")
		self.browser.select_form(nr=0)
		self.browser["email"] = self.email
		self.browser["pass"] = self.password
		self.response = self.browser.submit()
		self.data = self.response.read()
		
		while True:
			try:
				self.autopirate()
			except (URLError, HTTPError, HTTPDefaultErrorHandler):
				pass
			except LinkNotFoundError:
				pass
			except (KeyboardInterrupt, SystemExit):
				exit(1)

	def autopirate(self):
		handler_table = {
				"Error" : self.error,
				"explore the open sea" : self.explore,
				"keep exploring" : self.direction,
				"row yer boat" : self.explore,
				"explore a little further" : self.explore,
				"explore north" : self.direction,
				"spot some land" : self.approach_land,
				"small deserted island" : self.at_island,
				"return to sailin": self.return_to_sailin,
				"spot a ship" : self.spot_ship,
				"You found an Enemy Ship" : self.attack_ship,
				"FIRE" : self.fighting,
				"You WON" : self.sail_away,
				"Sail away" : self.sail_away,
				"throw a bomb" : self.throw_bomb,
				"Throw some bombs": self.throw_bomb,
				"Some friends who have gold": self.throw_bomb,
				"threw a bomb": self.throw_bomb,
				"found an enemy island" : self.pillaging,
				"Arrrr..... Keep on sailin" : self.healing,
				"You are fished out": self.bad_weather,
				"crew demands rest" : self.resting,
				}
			
		handled = False
		for key in handler_table.keys():
			if key in self.data:
				handler = handler_table[key]
				handler()
				handled = True
				break

		if not handled:
			self.getURL("index.php")

	def getconf(self):
		file = path.expanduser("~/.piraterc")
		if not path.exists(file):
			self.log("No configuration file found.")
			exit(1)
		if oct(stat(file)[0]) != "0100600":
			self.log("Insecure configuration file permission.")
			exit(1)
		config_file = ConfigParser()
		config_file.read(file)
		return (config_file.get("login", "email"), \
			config_file.get("login", "password"))

	def getURL(self, page):
		url = "http://apps.facebook.com/pirates/" + page
		self.response = self.browser.open(url)
		self.data = self.response.read()

	def postURL(self, page, postdata):
		url = "http://apps.facebook.com/pirates/" + page
		self.response = self.browser.open(url, postdata)
		self.data = self.response.read()
		
	def submitForm(self, form):
		self.browser.select_form(nr=form)
		self.response = self.browser.submit()
		self.data = self.response.read()

	def log(self, message):
		message = sub('\n', '', message)
		message = sub('  ', ' ', message)
		time = strftime("%x - %X")
		print "%s >> %s" % (time, message)

	def error(self):
		self.log("Server error.")
		self.getURL("index.php")

	def explore(self):
		message = compile('font-size: 125%;">([^\-]+)--&gt;<')
		message = message.findall(self.data)[0].rstrip()
		self.items = {
				"miles" : '\d+(?= miles away)',
				"level" : 'Level ([a-zA-Z0-9\s]) Pirate',
				"hits" : '(?<=Hit Points: )\d+',
				"coins" : '(?<=Coins: )[0-9,]+',
				"buried" : '(?<=Buried: )[0-9,]+'
				}
			
		for key in self.items.keys():
			val = compile(self.items[key])
			val = val.findall(self.data)
				
			if len(val):
				self.items[key] = val[0]
			else: self.items[key] = '0'
				
		self.log("(M:%s L:%s H:%s C:%s B:%s) %s." % \
				(self.items['miles'], self.items['level'], \
				self.items['hits'], self.items['coins'], \
				self.items['buried'], message))
		
		self.getURL("explore.php")

	def approach_land(self):
		self.log("Approaching some land.")
		self.getURL("head_towards_land.php")

	def at_island(self):
		if "Bury yer" in self.data:
			coins = search('(?<=Bury yer )\d+', self.data)
			if int(coins.group(0)) > 200:
				self.log("Bury %s coins." % coins.group(0))
				self.getURL("bury_coins_arr.php")
			else:
				self.log("Search from some booty items.")
				self.getURL("island_booty.php")
		else:	
			self.log("Search from some booty items.")
			self.getURL("island_booty.php")

	def return_to_sailin(self):
		i = compile('(?:="status"\>)([^<>]+)(?:<br />)([^<>]+)')
		item = i.findall(self.data)
		status = item[0][0] + " " + item[0][1]
		self.log("%s" % (status))
		self.getURL("index.php")

	def direction(self):
		directions = ["north", "south"]
		direction = choice(directions)
		miles = compile("\d+(?= miles away)")
		miles = miles.findall(self.data)
		self.log("%s miles. Sailing to %s." % (miles[0], direction))
		self.getURL("explore.php?d=" + direction)

	def spot_ship(self):
		self.log("Spot a ship!")
		self.getURL("enemy_ship.php")
		
	def attack_ship(self):
		self.log("Attack!")
		self.getURL("attack_ship.php")
		
	def sail_away(self):
			clean = sub('(\n|\t)', '', self.data)
			stat = compile('10px;"><h2>(.+?)</h2>')
			stat = stat.findall(clean)
			if len(stat):
				status = stat[0]
				status = sub('<([^>]+)>', '', status)
			else:
				status = " "
				
			self.log("%s" % (status))
			self.getURL("index.php")
	
	def fighting(self):
			stat = compile('<h\d{1} class="status">(.+?)<p>')
			stat = stat.findall(self.data)
			if len(stat):
				status = stat[0]
				status = sub('<([^>]+)>', '', status)
			else: 
				status = " "
				
			self.log("%s" % (status))
			clean = sub('\n', '', self.data)
			position = compile('<tr><td>(.*?)</td><td>(.*?)</td><td align="center">(.*?)</td></tr>')
			position = position.findall(clean)

			form = 2
			pos = 'FIRE STRAIGHT!!'
			
			if len(position[0][0]):
				form = 1
				pos = 'FIRE LEFT!!'
			elif len(position[0][2]):
				form = 3
				pos = 'FIRE RIGHT!!'
			
			self.log("%s" % pos.title())
			self.submitForm(form)
			
	def throw_bomb(self):
		if 'throw a bomb!' in self.data:
			self.log("Throw bomb!")
			self.getURL("throw_bomb_which.php")
		
		elif 'Throw some bombs!' in self.data:
			self.log("Throw a bomb at a Pirate.")
			self.getURL("throw_bomb_pick_pirate.php")
		
		elif 'Some friends who have gold' in self.data:
			search = compile('<h2(?:[^>]+)><a(?:[^>]+)>([a-zA-Z0-9\s]+)</a>\s?([a-zA-Z0-9\s]+)\s?<a href="([^"]+)"(?:[^>]+)><br />THROW BOMB!</a></h2>')
			friend = search.findall(self.data)
			
			if len(friend):
				self.log("%s %s" % (friend[0][0], friend[0][1]))
				self.getURL(friend[0][2])
			else:
				self.log("Too bad, no one has gold!")
				self.getURL("clear_action.php")
		
		elif 'threw a bomb' in self.data:
			search = compile('<div style="padding-top: 25px;">([a-zA-Z\s\!]+)<a(?:[^>]+)>([a-zA-Z]+)\s?</a>\s?([a-zA-Z0-9\s!]+)</div>')
			message = search.findall(self.data)
			
			if len(message):
				self.log("%s %s %s" % (message[0][0], 
					message[0][1], message[0][2]))
			else:
				self.log("You threw a bomb, and stole 0 coins!")
				
			self.getURL("explore.php")
		
		else:
			self.log("Too bad, no one has gold!")
			self.getURL("clear_action.php")
			
	def pillaging(self):
		self.getURL("pillage_town.php")
		post = {}
		
		for n in range(1, 16):
			post["house" + str(n)] = "house"
		post["houseCount"] = n
		
		postdata = urlencode(post)
		self.log("Attack a town.")
		self.postURL("process_pillaging_results.php", postdata)

		pillaged = compile("\d+ coins pillaged").findall(self.data)

		if not pillaged:
			coins = "0 coins"
		else:
			coins = pillaged[0]
			
		self.log("Got %s." % coins)
		self.getURL("index.php")

	def healing(self):
		if 'bombed' or 'attacked' in self.data:
			message = compile('([^>]+)</a> (\(Level \d+\)) (\w+) you!')
			message = message.findall(self.data)
			if not message: message = [[' ', '0', ' '],]
			self.log("%s %s %s you!" % (message[0][0], \
					message[0][1], message[0][2]))
			self.getURL("clear_was_attacked.php")
		else:
			self.log("Keep on sailin.")
			self.getURL("index.php")
	
	def bad_weather(self):
		stat = compile('id="error">(?:[^<]+)<br />([^<]+)<')
		stat = stat.findall(self.data)
		if len(stat):
			status = stat[0]
		self.log("Bad weather: %s" % (status))
		self.getURL("index.php")
		
	def resting(self):
		self.log("Reach sail limit.")
		exit(1)
		
if __name__ == "__main__":
	pirates().start()
